package com.fyt.reachgo.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fyt.reachgo.config.RabbitMQConfig;
import com.fyt.reachgo.domain.Result;
import com.fyt.reachgo.domain.TravelComment;
import com.fyt.reachgo.domain.User;
import com.fyt.reachgo.domain.dto.CommentDTO;
import com.fyt.reachgo.domain.dto.UserDTO;
import com.fyt.reachgo.domain.message.CommentLikeMessage;
import com.fyt.reachgo.mapper.CommentLikeMapper;
import com.fyt.reachgo.mapper.UserMapper;
import com.fyt.reachgo.service.TravelCommentService;
import com.fyt.reachgo.mapper.TravelCommentMapper;
import com.fyt.reachgo.utils.UserHolder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.fyt.reachgo.utils.RedisConstants.CACHE_TRAVEL_GUIDE_COMMENTS_KEY;
import static com.fyt.reachgo.utils.RedisConstants.CACHE_TRAVEL_GUIDE_LIST_KEY;

/**
* @author 27675
* @description 针对表【travel_comment(旅行路书评论表)】的数据库操作Service实现
* @createDate 2025-04-07 10:52:01
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class TravelCommentServiceImpl extends ServiceImpl<TravelCommentMapper, TravelComment>
    implements TravelCommentService{

    private final TravelCommentMapper commentMapper;
    private final UserMapper userMapper;
    private final CommentLikeMapper commentLikeMapper;
    private final RedisTemplate<String, Object> redisTemplate;
    private final RabbitTemplate rabbitTemplate;
    private final StringRedisTemplate stringRedisTemplate;


    @Override
    public List<TravelComment> getCommentsByGuideId(Integer guideId, Integer page, Integer size) {
        // 查询缓存
        String key = CACHE_TRAVEL_GUIDE_COMMENTS_KEY + guideId + ":" + page + ":" + size;
        // 如果缓存存在
        if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) {
            log.debug("缓存命中：{}", key);
            // 解决缓存穿透
            String json = stringRedisTemplate.opsForValue().get(key);
            if (StrUtil.isBlank(json)) {
                // 解决缓存穿透
                return null;
            }
            return JSONUtil.toList(json, TravelComment.class);
        }

        // 缓存不存在，查询数据库
        log.debug("缓存未命中：{}", key);
        // 先查一级评论
        Page<TravelComment> commentPage = new Page<>(page, size);
        LambdaQueryWrapper<TravelComment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TravelComment::getTravelGuideId, guideId)
                .isNull(TravelComment::getParentId)
                .eq(TravelComment::getStatus, 1)
                .orderByDesc(TravelComment::getCreateTime);

        commentMapper.selectPage(commentPage, queryWrapper);
        List<TravelComment> comments = commentPage.getRecords();

        // 填充用户信息和子评论
        comments.forEach(comment -> {
            fillUserInfo(comment);
            fillReplies(comment);
        });

        // 对象转换为JSON字符串
        String json = JSONUtil.toJsonStr(comments);
        // 写入缓存
        stringRedisTemplate.opsForValue().set(key, json);
        // 加入过期时间
        stringRedisTemplate.expire(key, 5 + RandomUtil.randomLong(1, 10), TimeUnit.MINUTES);

        return comments;
    }

    @Override
    @Transactional
    public Long addComment(CommentDTO commentDTO) {
        // 验证路书是否存在
        // 验证用户是否存在
        // 如果是回复评论，验证父评论是否存在
        TravelComment comment = new TravelComment();
        BeanUtils.copyProperties(commentDTO, comment);
        // 设置用户id
        comment.setUserId(UserHolder.getUser().getUserId());

        // 设置根评论ID
        if (comment.getParentId() != null) {
            TravelComment parentComment = commentMapper.selectById(comment.getParentId());
            comment.setRootId(parentComment.getRootId() != null ? parentComment.getRootId() : parentComment.getId());
        }

        commentMapper.insert(comment);

        // 如果是回复评论，更新父评论的回复数
        if (comment.getParentId() != null) {
            updateReplyCount(comment.getParentId());
        }

        // 发送消息到MQ，用于后续处理（如通知被回复的用户）
        rabbitTemplate.convertAndSend(RabbitMQConfig.COMMENT_EXCHANGE,
                RabbitMQConfig.COMMENT_ADD_ROUTING_KEY,
                comment);

        return comment.getId();
    }

    @Override
    public Result likeComment(Long commentId) {
        Long userId = UserHolder.getUser().getUserId();

        // 使用Redis set判断是否已点赞
        String key = "comment:like:" + commentId;
        if (Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, userId))) {
            return Result.error("您已经点过赞了");
        }

        // 异步处理点赞
        CommentLikeMessage message = new CommentLikeMessage(commentId, userId, true);
        rabbitTemplate.convertAndSend(RabbitMQConfig.COMMENT_EXCHANGE,
                RabbitMQConfig.COMMENT_LIKE_ROUTING_KEY,
                message);

        // 更新Redis缓存
        redisTemplate.opsForSet().add(key, userId);
        redisTemplate.opsForValue().increment("comment:like:count:" + commentId);
        return Result.success("点赞成功");
    }

    @Override
    public Result unlikeComment(Long commentId) {
        Long userId = UserHolder.getUser().getUserId();

        // 使用Redis set判断是否已点赞
        String key = "comment:like:" + commentId;
        if (Boolean.FALSE.equals(redisTemplate.opsForSet().isMember(key, userId))) {
            return Result.error("您还没有点赞");
        }

        // 异步处理取消点赞
        CommentLikeMessage message = new CommentLikeMessage(commentId, userId, false);
        rabbitTemplate.convertAndSend(RabbitMQConfig.COMMENT_EXCHANGE,
                RabbitMQConfig.COMMENT_LIKE_ROUTING_KEY,
                message);

        // 更新Redis缓存
        redisTemplate.opsForSet().remove(key, userId);
        redisTemplate.opsForValue().decrement("comment:like:count:" + commentId);
        return Result.success("取消点赞成功");
    }
//
//    @Override
//    @Transactional
//    public void deleteComment(Long commentId) {
//        TravelComment comment = commentMapper.selectById(commentId);
//        if (comment == null) {
//            throw new BusinessException("评论不存在");
//        }
//
//        Long userId = getCurrentUserId();
//        if (!comment.getUserId().equals(userId)) {
//            throw new BusinessException("无权删除他人评论");
//        }
//
//        // 逻辑删除
//        comment.setStatus(0);
//        commentMapper.updateById(comment);
//
//        // 如果是回复评论，更新父评论的回复数
//        if (comment.getParentId() != null) {
//            updateReplyCount(comment.getParentId());
//        }
//    }

    private void fillUserInfo(TravelComment comment) {
        User user = userMapper.selectById(comment.getUserId());
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        comment.setUser(userDTO);
    }

    private void fillReplies(TravelComment comment) {
        LambdaQueryWrapper<TravelComment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TravelComment::getRootId, comment.getId())
                .eq(TravelComment::getStatus, 1)
                .orderByAsc(TravelComment::getCreateTime);

        List<TravelComment> replies = commentMapper.selectList(queryWrapper);
        replies.forEach(this::fillUserInfo);
        comment.setReplies(replies);
    }

    private void updateReplyCount(Long commentId) {

        LambdaQueryWrapper<TravelComment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TravelComment::getParentId, commentId)
                .eq(TravelComment::getStatus, 1);

        Integer count = Math.toIntExact(commentMapper.selectCount(queryWrapper));
        TravelComment comment = new TravelComment();
        comment.setId(commentId);
        comment.setReplyCount(count);
        commentMapper.updateById(comment);
    }



}




